package main

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"github.com/parnurzeal/gorequest"
	"strconv"
	"strings"
	"time"
)

var hp *HttpProcess
var HttpTimeOut int

var beelog = logs.NewLogger(10)

func initDB(dsn string) {
	// set default database
	maxIdle := 10
	maxConn := 10
	err := orm.RegisterDataBase("default", "mysql", dsn, maxIdle, maxConn)
	if err != nil {
		beelog.Error(err.Error())
	}
	// register model
	orm.RegisterModel(new(Domains))
	// create table
	err = orm.RunSyncdb("default", false, true)
	if err != nil {
		beelog.Error(err.Error())
	}
}

func DomainsListAll() []Domains {
	var domains []Domains
	o := orm.NewOrm()
	//_, err := o.QueryTable("domains").All(&domains)
	_, err := o.QueryTable("domains").Limit(1000000).Filter("desc", "YES").All(&domains)

	if err != nil {
		beelog.Error(`DomainsListAll,o.QueryTable("domains").All(&domains)`)
	}
	return domains
}

func DomainsUpdate(data *Domains) error {
	if _, err := orm.NewOrm().Update(data); err != nil {
		return err
	}
	return nil
}

// Model Struct
type Domains struct {
	Id         int
	Url        string    `orm:"type(text)"`
	Ip         string    `orm:"size(100);default(0.0.0.0)"`
	StatusCode int       `orm:"default(1)"`
	Desc       string    `orm:"size(100);default(YES)"`
	CostTime   float64   `orm:"digits(12);decimals(4)"`
	Created    time.Time `orm:"auto_now_add;type(datetime)"`
	Updated    time.Time `orm:"auto_now;type(datetime)"`
}

type HttpProcess struct {
	rc    chan Domains
	wc    chan Domains
	dbDsn string
}

func (d *HttpProcess) ReadFrom() {
	//从数据库读取url
	for {
		beelog.Info("start ReadFrom DB")
		domainList := DomainsListAll()
		for _, value := range domainList {
			line := value
			d.rc <- line
		}
		time.Sleep(60 * time.Second)
	}

}
func GetBetweenStr(str, start, end string) string {
	n := strings.Index(str, start)
	if n == -1 {
		n = 0
	}
	str = string([]byte(str)[n+len(start):])

	m := strings.Index(str, end)
	if m == -1 {
		m = len(str)
	}
	str = string([]byte(str)[:m])
	return str
}

func (d *HttpProcess) Process() {
	//http访问
	for v := range d.rc {
		t1 := time.Now()
		if v.Ip == "0.0.0.0" {
			resp, _, errs := gorequest.New().Get(v.Url).
				Set("monitor-hj", "7BCDB077276BEC8A9D2CE39548B5D57E").
				Set("User-Agent", "hjops").
				Timeout(time.Duration(HttpTimeOut) * time.Second).
				End()
			//fmt.Println(resp,body,errs)

			elapsed := time.Since(t1)
			v.CostTime = elapsed.Seconds()
			if errs != nil {
				beelog.Error("http get error: %s", errs)
				v.StatusCode = 0
			} else {
				v.StatusCode = resp.StatusCode

			}

		} else {
			da := GetBetweenStr(v.Url, "//", "/")
			du := strings.Replace(v.Url, da, v.Ip, 1)
			resp, _, errs := gorequest.New().Get(du).
				Set("monitor-hj", "7BCDB077276BEC8A9D2CE39548B5D57E").
				Set("User-Agent", "hjops").
				Set("Host", da).
				Timeout(time.Duration(HttpTimeOut) * time.Second).
				End()

			elapsed := time.Since(t1)
			v.CostTime = elapsed.Seconds()
			if errs != nil {
				beelog.Error("http get error: %s,%s", errs, da)
				v.StatusCode = 0
			} else {
				v.StatusCode = resp.StatusCode

			}
		}

		d.wc <- v
	}
}

func (d *HttpProcess) WritOut() {
	//写出到数据库
	for v := range d.wc {
		err := DomainsUpdate(&v)
		if err != nil {
			beelog.Error(err.Error())
		}

	}
}

type MainController struct {
	beego.Controller
}

func (c *MainController) Get() {
	c.Ctx.WriteString("The length of hp.rc=" + strconv.Itoa(len(hp.rc)) + "\nThe length of hp.wc=" + strconv.Itoa(len(hp.wc)) + "\n")
}

func main() {
	//orm.Debug = true
	rclen, _ := beego.AppConfig.Int("rclen")
	wclen, _ := beego.AppConfig.Int("wclen")
	gothread, _ := beego.AppConfig.Int("gothread")
	HttpTimeOut, _ = beego.AppConfig.Int("httptimeout")
	beelog.Info("%s,%s,%s", rclen, wclen, gothread)
	//beelog.SetLogger(logs.AdapterConsole)
	err := beelog.SetLogger(logs.AdapterFile, `{"filename":"httpget.log","level":7,"maxlines":0,"maxsize":0,"daily":true,"maxdays":10,"color":true}`)
	if err != nil {
		beelog.Error(err.Error())
	}
	hp = &HttpProcess{
		rc:    make(chan Domains, rclen),
		wc:    make(chan Domains, wclen),
		dbDsn: beego.AppConfig.String("mysqldsn"),
	}

	initDB(hp.dbDsn)
	go hp.ReadFrom()

	for i := 0; i < gothread; i++ {
		go hp.Process()
	}
	go hp.WritOut()

	beego.Router("/", &MainController{})
	beego.Run()
}
